package com.sky.common.http;


import com.sky.common.http.common.NoneHostnameVerifier;
import com.sky.common.http.exception.HttpBuildException;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * http客户端构造
 */
public class HttpDecorateBuilder {

    private HttpClientBuilder httpClientBuilder;
    private SSLConnectionSocketFactory sslConnectionSocketFactory;
    private HttpClientConnectionManager httpClientConnectionManager;

    private static Registry<ConnectionSocketFactory> registry(SSLConnectionSocketFactory sslConnectionSocketFactory) {
        return RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslConnectionSocketFactory)
                .build();
    }


    public static HttpDecorateBuilder create() {
        HttpDecorateBuilder decorator = new HttpDecorateBuilder();
        RequestConfig resConf = RequestConfig.custom().setConnectTimeout(50000).setSocketTimeout(50000).setConnectionRequestTimeout(50000).build();
        decorator.httpClientBuilder = HttpClientBuilder.create().setDefaultRequestConfig(resConf);
        decorator.sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory();
        return decorator;
    }


    public static HttpDecorateBuilder createWithCertAndCa(String certPath, String certPwd, String trustCaPath, String trustCaPwd) {
        HttpDecorateBuilder decorator = new HttpDecorateBuilder();
        decorator.httpClientBuilder = HttpClientBuilder.create();
        try {
            KeyStore selfCert = KeyStore.getInstance("pkcs12");
            selfCert.load(new FileInputStream(certPath), certPwd.toCharArray());
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("sunx509");
            kmf.init(selfCert, certPwd.toCharArray());
            KeyStore caCert = KeyStore.getInstance("jks");
            caCert.load(new FileInputStream(trustCaPath), trustCaPwd.toCharArray());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("sunx509");
            tmf.init(caCert);
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
            decorator.sslConnectionSocketFactory = new SSLConnectionSocketFactory(sc, new NoneHostnameVerifier());
            //默认不是连接池
            decorator.httpClientConnectionManager = new BasicHttpClientConnectionManager(registry(decorator.sslConnectionSocketFactory));
        } catch (IOException e) {
            throw new HttpBuildException("加载https证书文件异常", e);
        } catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyManagementException | KeyStoreException | CertificateException ex) {
            throw new HttpBuildException("加载https证书异常", ex);
        }
        return decorator;
    }

    public static HttpDecorateBuilder createWithCert(String password, String certPath) {
        HttpDecorateBuilder decorator = new HttpDecorateBuilder();
        decorator.httpClientBuilder = HttpClientBuilder.create();
        try {
            char[] passwordChars = password.toCharArray();
            InputStream certStream = new FileInputStream(certPath);
            KeyStore ks = KeyStore.getInstance("PKCS12");
            ks.load(certStream, passwordChars);
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            kmf.init(ks, passwordChars);
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
            decorator.sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null, new DefaultHostnameVerifier());
            decorator.httpClientConnectionManager = new BasicHttpClientConnectionManager(registry(decorator.sslConnectionSocketFactory));
        } catch (IOException var9) {
            throw new HttpBuildException("加载https证书文件异常", var9);
        } catch (UnrecoverableKeyException | KeyManagementException | CertificateException | NoSuchAlgorithmException | KeyStoreException var10) {
            throw new HttpBuildException("加载https证书异常", var10);
        }
        return decorator;
    }

    public static HttpDecorateBuilder createWithTrustSSLContent() {
        HttpDecorateBuilder decorator = new HttpDecorateBuilder();
        decorator.httpClientBuilder = HttpClientBuilder.create();
        try {
            SSLContext sc = SSLContext.getInstance("TLSv1.2");
            X509TrustManager trustManager = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            sc.init(null, new TrustManager[]{trustManager}, null);
            decorator.sslConnectionSocketFactory = new SSLConnectionSocketFactory(sc, NoopHostnameVerifier.INSTANCE);
            decorator.httpClientConnectionManager = new BasicHttpClientConnectionManager(registry(decorator.sslConnectionSocketFactory));
        } catch (Exception var2) {
            throw new HttpBuildException("构建https异常", var2);
        }
        return decorator;
    }

    public HttpDecorateBuilder pool(int maxTotal, int maxPreRoute) {
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(
                registry(this.sslConnectionSocketFactory));
        //维护的httpclientConnection总数
        poolingHttpClientConnectionManager.setMaxTotal(maxTotal);
        // 路由数量
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(maxPreRoute);
        this.httpClientConnectionManager = poolingHttpClientConnectionManager;
        return this;
    }


    public HttpDecorateBuilder credsProvider(String proxyUser,String proxyPass){
        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(proxyUser, proxyPass));
        httpClientBuilder.setDefaultCredentialsProvider(credsProvider);
        return this;
    }

    public HttpDecorateBuilder proxy(String hostname, int port) {
        this.httpClientBuilder.setProxy(new HttpHost(hostname, port));
        return this;
    }

    public HttpDecorateBuilder connectionManager(HttpClientConnectionManager httpClientConnectionManager) {
        this.httpClientConnectionManager = httpClientConnectionManager;
        return this;
    }

    public HttpDecorateBuilder disableCookieManagement(){
        this.httpClientBuilder.disableCookieManagement();
        return this;
    }

    /**
     * 其他方法... 对httpClientBuilder 设置
     */
    public HttpDecorate build() {
        httpClientBuilder.setConnectionManager(httpClientConnectionManager);
        return new HttpDecorate(httpClientBuilder.build());
    }
}
